using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Threading;

using Dashboard.Util;

namespace Dashboard.Engine.Transports
{
	// This is a generic connection handler using XML
	// serialization for the Unix and TCP stream 
	// transports.

	internal abstract class XmlConnectionHandler
	{
		private static ThreadPond thread_pond = null;

		private Thread thread = null;
		private object client_lock = new object ();

		public event EventHandler Canceled;

		static XmlConnectionHandler ()
		{
			thread_pond = new ThreadPond (10);
			thread_pond.Start ();
		}

		public XmlConnectionHandler ()
		{
			
		}

		public void Start ()
		{
			// FIXME: Fix the thread-pool.
			//thread_pond.Add (new ThreadStart (Worker_Locked));
			
			thread = new Thread (new ThreadStart (Worker_Locked));
			thread.Start ();			
		}

		public abstract void Close ();
		
		private void Worker_Locked ()
		{
			// Read the data off the socket and store it in a
                        // temporary memory buffer.  Once the end-of-message
                        // character has been read (0xff), discard remaining data,
                        // deserialize the request and listen for other incoming data
			// until the remote socket is closed.

			do {
				Worker_Unlocked ();
			} while (!Closed);
		}

		private void Worker_Unlocked ()
		{
			Engine.Log.Debug ("Worker started");

                        byte[] network_data = new byte [4096];
                        MemoryStream buffer_stream = new MemoryStream ();
                        int bytes_read, total_bytes = 0, end_index = -1;

                        do {
                                bytes_read = 0;

                                try {
                                        lock (client_lock) {
                                                // The connection may have been closed within this loop.
                                                if (!Closed)
                                                        bytes_read = Stream.Read (network_data, 0, 4096);
                                        }
                                } catch (Exception e) {
                                        // Aborting the thread mid-read will
                                        // cause an IOException to be thorwn,
                                        // which sets the ThreadAbortException
                                        // as its InnerException.

                                        if (!(e is IOException || e is ThreadAbortException))
                                                throw;

                                        Engine.Log.Debug ("Bailing out of HandleConnection -- shutdown requested");
                                        return;
                                }

                                total_bytes += bytes_read;

                                if (bytes_read > 0) {
                                        // 0xff signifies end of message
                                        end_index = ArrayFu.IndexOfByte (network_data, (byte) 0xff);
                                        buffer_stream.Write (network_data, 0, end_index == -1 ? bytes_read : end_index);
                                }
                        } while (bytes_read > 0 && end_index == -1);

			// If we recieved any data, try to deserialize
			// them into a message.

                        if (total_bytes > 0) {
				Message message = null;
				
				buffer_stream.Seek (0, SeekOrigin.Begin);
				
				try {
					message = Message.Serializer.Deserialize (buffer_stream) as Message;
				} catch (Exception e) {
					Engine.Log.Error ("Failed to deserialize message");
					Engine.Log.Error (e);
				}
				
				if (message != null)
					Engine.MessageBroker.Send (message);
				
			}

			// Cleanup all resources
			Engine.Log.Debug ("Worker cleanup");
		}

		protected abstract Stream Stream {
			get;
		}

		protected abstract bool Closed {
			get;
		}
	}
}
